package com.learnyou.server.xingzuo.biz.helper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author heweifeng
 * @Description:
 * @date 2022/12/4 15:10
 */
@Component
public class RedisGeoHelper {


    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 添加节点及位置信息
     * @param geoKey 位置集合
     * @param pointName 位置点标识
     * @param longitude 经度
     * @param latitude 纬度
     */
    public void geoAdd(String geoKey, String pointName, double longitude, double latitude){
        Point point = new Point(longitude, latitude);
        redisTemplate.opsForGeo().add(geoKey, point, pointName);
    }

    /**
     *
     * @param longitude
     * @param latitude
     * @param radius
     * @param geoKey
     * @param metricUnit 距离单位，例如 Metrics.KILOMETERS
     * @param metricUnit
     * @return
     */
    public List<GeoResult<RedisGeoCommands.GeoLocation<String>>> findRadius(String geoKey
            , double longitude, double latitude, double radius, Metrics metricUnit, int limit){
        // 设置检索范围
        Point point = new Point(longitude, latitude);
        Circle circle = new Circle(point, new Distance(radius, metricUnit));
        // 定义返回结果参数，如果不指定默认只返回content即保存的member信息
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                .newGeoRadiusArgs().includeDistance().includeCoordinates()
                .sortAscending()
                .limit(limit);
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(geoKey, circle, args);
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();
        return list;
    }


    /**
     * reids 附近地址分页查询
     * @param geoKey
     * @param longitude
     * @param latitude
     * @param current 当前页码
     * @param pageSize 每页数量
     * @param distance 指定搜索地理位置范围
     * @param metricUnit 距离单位
     * @return
     */
    public List<GeoResult<RedisGeoCommands.GeoLocation<String>>> geoSearch(String geoKey
            , double longitude, double latitude
            , Integer current, Integer pageSize
            , double distance, Metrics metricUnit
    ){
        //计算分页参数
        int from = (current - 1) * pageSize;
        int end = current * pageSize;

        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo() // GEOSEARCH key BYLONLAT x y BYRADIUS 10 WITHDISTANCE
                .search(
                        geoKey,
                        GeoReference.fromCoordinate(longitude, latitude),
                        new Distance(distance, metricUnit),
                        RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance().limit(end)
                );
        if (results == null) {
            return Collections.emptyList();
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();
        if (list.size() <= from) {
            // 没有下一页了，结束
            return Collections.emptyList();
        }

        return list.stream().skip(from).collect(Collectors.toList());
    }

    /**
     * 计算指定key下两个成员点之间的距离
     * @param geoKey
     * @param member1
     * @param member2
     * @param unit 单位
     * @return
     */
    public Distance calDistance(String geoKey, String member1, String member2
            , RedisGeoCommands.DistanceUnit unit){
        Distance distance = redisTemplate.opsForGeo()
                .distance(geoKey, member1, member2, unit);
        return distance;
    }

    /**
     * 根据成员点名称查询位置信息
     * @param geoKey geo key
     * @param members 名称数组
     * @return
     */
    public List<Point> geoPosition(String geoKey, String[] members){
        List<Point> points = redisTemplate.opsForGeo().position(geoKey, members);
        return points;
    }

    public List<String> geoHash(String geoKey, String... members) {

        return redisTemplate.opsForGeo().hash(geoKey, members);
    }
}
